package org.yray.somehttp.se.hsex;

import java.io.File;
import java.io.FileInputStream;
import java.security.KeyStore;
import java.util.LinkedList;
import java.util.List;
import java.util.function.Consumer;

import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SNIMatcher;
import javax.net.ssl.SNIServerName;
import javax.net.ssl.SSLEngine;
import javax.net.ssl.SSLParameters;
import javax.net.ssl.TrustManagerFactory;

import cn.hutool.core.io.FileUtil;
import org.springframework.http.client.reactive.ClientHttpConnector;
import org.springframework.http.client.reactive.ReactorClientHttpConnector;
import org.springframework.web.reactive.function.client.WebClient;

import io.netty.handler.ssl.SslContext;
import io.netty.handler.ssl.SslContextBuilder;
import io.netty.handler.ssl.util.InsecureTrustManagerFactory;
import reactor.core.publisher.Mono;
import reactor.netty.http.client.HttpClient;
import reactor.netty.tcp.SslProvider.SslContextSpec;

/**
 * 通过WebClient调用Https接口
 */
public class WebClientHttpsCase {
    public static void main(String[] args) {
        try {
            sendTrust();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private static void both() throws Exception {
        String requestPath = "https://10.40.103.48:9016/zsywservice/";
        KeyStore keyStore = getkeyStore("pkcs12", "d:/client.p12", "123456");
        KeyStore trustStore = getkeyStore("jks", "d:/temp/cacerts", "123456");
        WebClient webClient = WebClient.builder().clientConnector(getClientHttpConnector(keyStore, "123456", trustStore)).build();
        Mono<String>  mono = webClient.get().uri(requestPath).retrieve().bodyToMono(String.class);
        System.out.println("get3返回结果：" + mono.block());
    }
    private static void sendTrust() throws Exception {
        /*HttpClient secure = HttpClient.create()
                .secure(t -> t.sslContext(SslContextBuilder.forClient().trustManager(InsecureTrustManagerFactory.INSTANCE)));
        WebClient webClient= WebClient.builder()
                .clientConnector(new ReactorClientHttpConnector(secure))
                .build();*/
        //KeyStore trustStore = getkeyStore("jks", "d:/cert/csdn.cer", "123456");
        WebClient webClient = WebClient.builder().clientConnector(getClientHttpConnector(null)).build();
        //不需要客户端证书
        webClient.options().header("user-agent","Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/111.0.0.0 Safari/537.36 Edg/111.0.1661.62");
        String requestPath = "https://hsex.men/video-798610.htm";
        Mono<String> mono = webClient.get().uri(requestPath).retrieve().bodyToMono(String.class);
        System.out.println("get2返回结果：" + mono.block());
    }

    /*
     * 请求自定义证书的地址
     */
    private static void sendTrustCustom() throws Exception {
        //获取信任证书库
        KeyStore trustStore = getkeyStore("jks", "d:/temp/cacerts", "123456");
        //不需要客户端证书
        String requestPath = "https://10.40.103.48:9010/zsywservice/";
        WebClient webClient = WebClient.builder().clientConnector(getClientHttpConnector(trustStore)).build();
        Mono<String> mono = webClient.get().uri(requestPath).retrieve().bodyToMono(String.class);
        System.out.println("get2返回结果：" + mono.block());
    }
    /*
     * 请求有权威证书的地址
     */
    private static void sendNone()
    {

        WebClient webClient = WebClient.create();
        webClient.options().header("user-agent","Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/111.0.0.0 Safari/537.36 Edg/111.0.1661.62");
        webClient.options().header("sec-ch-ua","\"Microsoft Edge\";v=\"111\", \"Not(A:Brand\";v=\"8\", \"Chromium\";v=\"111\"");
        webClient.options().header("accept","text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7");
        String requestPath = "https://hsex.men/video-798610.htm";
        Mono<String> mono = webClient.get().uri(requestPath).retrieve().bodyToMono(String.class);
        System.out.println("get1返回结果：" + mono.block());
    }

    /**
     * 获取Connector
     * @param keyStore
     * @param password
     * @return
     * @throws Exception
     */
    private static ClientHttpConnector getClientHttpConnector(KeyStore keyStore, String keyStorePassword, KeyStore trustStore) throws Exception {
        SslContextBuilder builder = SslContextBuilder.forClient();
        if (keyStore != null) {
            KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance("SunX509");
            keyManagerFactory.init(keyStore, keyStorePassword.toCharArray());
            builder.keyManager(keyManagerFactory);
        }
        if (trustStore != null) {
            TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance("SunX509");
            trustManagerFactory.init(trustStore);
            builder.trustManager(trustManagerFactory);
        } else {
            builder.trustManager(InsecureTrustManagerFactory.INSTANCE);
        }
        SslContext sslContext = builder.build();
        HttpClient httpClient = HttpClient.create().secure(new Consumer<SslContextSpec>() {
            @Override
            public void accept(SslContextSpec t) {
                t.sslContext(sslContext).handlerConfigurator(handler -> {
                    SSLEngine engine = handler.engine();
                    List<SNIMatcher> matchers = new LinkedList<SNIMatcher>();
                    SNIMatcher matcher = new SNIMatcher(0) {
                        @Override
                        public boolean matches(SNIServerName serverName) {
                            //if ("xxx".equals(serverName)) {
                            //    return true;
                            //} else {
                            //    return false;
                            //}
                            return true;
                        }
                    };
                    matchers.add(matcher);
                    SSLParameters params = new SSLParameters();
                    params.setSNIMatchers(matchers);
                    engine.setSSLParameters(params);
                });
            }
        });

        ClientHttpConnector connector = new ReactorClientHttpConnector(httpClient);
        return connector;
    }

    private static ClientHttpConnector getClientHttpConnector(KeyStore trustStore) throws Exception {
        return getClientHttpConnector(null, null, trustStore);
    }

    /**
     * 获取证书
     * @param type
     * @param filePath
     * @param password
     * @return
     */
    private static KeyStore getkeyStore(String type, String filePath, String password) {
        KeyStore keySotre = null;
        FileInputStream in = null;
        try {
            keySotre = KeyStore.getInstance(type);
            in = new FileInputStream(new File(filePath));
            keySotre.load(in, password.toCharArray());
        } catch (Exception e) {
            e.printStackTrace();
        } finally {

        }
        return keySotre;
    }
}